package cn.backflow.utils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Combination {

    public static void main(String[] args) {



        String val = "310|310|310|310|310|310|310|310|310|310|310|31|3|3";
        String[] arr = val.split("\\|");

        List<String[]> list = new ArrayList<>();

        long start = System.currentTimeMillis();
        split(arr, 10000, list);

        int sum = list.parallelStream().mapToInt(Combination::bets).sum();

        System.out.println(list.size() + "  " + sum);
        System.out.println(System.currentTimeMillis() - start);

        // List<String[]> strings = Combination.combination(bets, 9);
        // int sum = strings.stream().mapToInt(Combination::bets).sum();
        // System.out.println("共" + sum + "注");
    }

    private static void split(String[] arr, int threshhold, List<String[]> container) {
        int bets = bets(arr);
        if (bets >= threshhold) {
            for (String[] strings : split(arr)) {
                split(strings, threshhold, container);
            }
        } else {
            container.add(arr);
        }
    }

    // 拆分复式投注为若干子注
    private static String[][] split(String[] arr) {
        int max = 0, length = 0;
        for (int i = 0; i < arr.length; i++) {
            int len = arr[i].length();
            if (len > length) {
                length = len;
                max = i;
                if (length == 3) break;
            }
        }

        String val = arr[max];

        String[][] split = new String[length][arr.length];
        for (int i = 0; i < length; i++) {
            System.arraycopy(arr, 0, split[i], 0, arr.length);
            split[i][max] = String.valueOf(val.charAt(i));
        }

        return split;
    }

    private static int bets(String bet) {
        return bets(bet.split("\\|"));
    }

    private static int bets(String[] bets) {
        return Arrays.stream(bets)
                .mapToInt(String::length)
                .reduce(1, (left, right) -> left * right);
    }

    /**
     * 组合选择（从列表中选择n个组合）
     *
     * @param dataList 待选列表
     * @param n        选择个数
     */
    public static List<String[]> combination(String[] dataList, int n) {
        long total = c(dataList.length, n);
        System.out.println(String.format("C(%d, %d) = %d", dataList.length, n, total));
        List<String[]> result = new ArrayList<>();
        combination(dataList, 0, new String[n], 0, result);
        return result;
    }

    /**
     * 组合选择
     *
     * @param dataList    待选列表
     * @param dataIndex   待选开始索引
     * @param resultList  前面（resultIndex-1）个的组合结果
     * @param resultIndex 选择索引，从0开始
     */
    private static void combination(String[] dataList, int dataIndex, String[] resultList, int resultIndex, List<String[]> result) {
        int resultLen = resultList.length;
        int resultCount = resultIndex + 1;
        if (resultCount > resultLen) { // 全部选择完时，输出组合结果
            String[] arr = new String[resultLen];
            System.arraycopy(resultList, 0, arr, 0, resultLen);
            result.add(arr);
            return;
        }

        // 递归选择下一个
        for (int i = dataIndex; i < dataList.length + resultCount - resultLen; i++) {
            resultList[resultIndex] = dataList[i];
            combination(dataList, i + 1, resultList, resultIndex + 1, result);
        }
    }


    /**
     * 计算 C(m,n)个数 = (m!)/(n!*(m-n)!)
     * 从M个数中选N个数，函数返回有多少种选法 参数 m 必须大于等于 n m = 0; n = 0; retuan 1;
     */
    public static long c(int m, int n) {
        if (m < n)
            return 0; // 如果总数小于取出的数，直接返回0

        int j = 1, k = 1;
        // 该种算法约掉了分母的(m-n)!,这样分子相乘的个数就是有n个了
        for (int i = n; i >= 1; i--, m--, n--) {
            k *= m;
            j *= n;
        }
        return k / j;
    }

    private static int cc(int m, int n) {
        double temp = 1; //temp 为答案
        if (n < m - n) //保证n>=m-n
            return cc(m, m - n);
        for (int i = 0; i < m - n; ++i) {
            temp *= n + i + 1;
            temp /= i + 1;
        }

        return (int) temp;
    }


    /**
     * 计算组合数，即C(m, n) = m!/((m-n)! * n!)
     *
     * @param m
     * @param n
     */
    public static long combination(int m, int n) {
        return (m >= n) ? factorial(m) / factorial(m - n) / factorial(n) : 0;
    }

    /**
     * 计算阶乘数，即n! = n * (n-1) * ... * 2 * 1
     */
    public static long factorial(int n) {
        return (n > 1) ? n * factorial(n - 1) : 1;
    }
}
